package ig.formato.util;

import java.math.BigDecimal;
import java.util.Stack;
import java.util.StringTokenizer;

public class Matematica {

    public Matematica() {
    }

    public static String organizeFormula(String ecuacion, boolean addReturn) {
        ecuacion = ecuacion.trim();
        ecuacion += "true false";
        ecuacion = ecuacion.startsWith("(") ? ecuacion : "(" + ecuacion;
        ecuacion = ecuacion.endsWith(")") ? ecuacion : ecuacion + ")";
        //ecuacion = organizeFormula(ecuacion);
        return ecuacion;
    }

    public static String organizeFormula(String ecuacion) {
        ecuacion = ecuacion.replaceAll("\\(", " \\( ");
        ecuacion = ecuacion.replaceAll("\\)", " \\) ");
        ecuacion = ecuacion.replace("=", "= ");
        /*ecuacion = ecuacion.replace("<>", " <> ");
        ecuacion = ecuacion.replace("<=", " <= ");
        ecuacion = ecuacion.replace(">=", " >= ");
        ecuacion = ecuacion.replace(">", " > ");
        ecuacion = ecuacion.replace("<", " < ");
        ecuacion = ecuacion.replace(">", " > ");
        ecuacion = ecuacion.replace("=", " = ");        
         ///*;/;+;-;*;>;<;=;;*/

        return ecuacion;
    }

    public static String evaluaExpresion(String ecuacion, String tipoRegistro, String campo) throws IGFormatoException {

//        if(ecuacion.equals("( IF ( = C_013 C_013 ) 1 ( IF ( = C_013 C_014 ) 1 0 ) )"))
//        System.out.print("ecuacion:"+ecuacion+":");
        //ecuacion = ecuacion.replaceAll("\\(", " \\( ");
        //ecuacion = ecuacion.replaceAll("\\)", " \\) ");
        ecuacion = Matematica.organizeFormula(ecuacion);
        Object dres = null;
        StringTokenizer stz = new StringTokenizer(ecuacion, " \t\n");
        String str = "";
        Stack s = new Stack();
        Stack op = new Stack();
        try {
            while (stz.hasMoreTokens()) {
                str = stz.nextToken();
                if (stz.countTokens() == 0 && (str.startsWith("C_") || str.startsWith("F_") || str.startsWith("N_"))) {
                    str = str.substring(2, str.length());
                }
                if (str.compareTo(")") == 0) {
                    while ("(".compareTo((String) s.peek()) != 0) {
                        str = (String) s.pop();
                        if ("*;/;+;-;*;>=;<=;>;<;=;<>;!=;round;ROUND;Round;".indexOf((new StringBuilder()).append(";").append(str).append(";").toString()) > 0) {
                            boolean N = true;
                            String POP = (String) op.pop();
                            String POP_2 = (String) op.pop();
                            if (POP.toUpperCase().startsWith("N_") || POP.toUpperCase().startsWith("C_") || POP.toUpperCase().startsWith("F_")) {
                                String CARACTRE1 = POP.substring(0, 2);
                                String CARACTRE2 = POP_2.substring(0, 2);
                                if (!CARACTRE1.toUpperCase().trim().equals(CARACTRE2.toUpperCase().trim())) {
                                    str = "=";
                                    POP = "a";
                                    POP_2 = "b";
                                } else {
                                    POP = POP.substring(2, POP.length());
                                    POP_2 = POP_2.substring(2, POP_2.length());
                                }
                            }
                            if (str.compareTo("/") == 0) {
                                dres = new BigDecimal(POP);
                                str = ((BigDecimal) dres).divide(new BigDecimal(POP_2), 20, 4).toString();
                            } else if (str.compareTo("+") == 0) {
                                dres = new BigDecimal(POP);
                                str = ((BigDecimal) dres).add(new BigDecimal(POP_2)).toString();
                            } else if (str.compareTo("-") == 0) {
                                dres = new BigDecimal(POP);
                                str = ((BigDecimal) dres).subtract(new BigDecimal(POP_2)).toString();
                            } else if (str.compareTo("*") == 0) {
                                dres = new BigDecimal(POP);
                                str = ((BigDecimal) dres).multiply(new BigDecimal(POP_2)).toString();
                            } else if (str.compareTo(">=") == 0) {
                                dres = new BigDecimal(POP);
                                str = String.valueOf(((BigDecimal) dres).compareTo(new BigDecimal(POP_2)) >= 0);
                            } else if (str.compareTo("<=") == 0) {
                                dres = new BigDecimal(POP);
                                str = String.valueOf(((BigDecimal) dres).compareTo(new BigDecimal(POP_2)) <= 0);
                            } else if (str.compareTo(">") == 0) {
                                dres = new BigDecimal(POP);
                                str = String.valueOf(((BigDecimal) dres).compareTo(new BigDecimal(POP_2)) > 0);
                            } else if (str.compareTo("<") == 0) {
                                dres = new BigDecimal(POP);
                                str = String.valueOf(((BigDecimal) dres).compareTo(new BigDecimal(POP_2)) < 0);
                            } else if (str.compareTo("=") == 0 || str.compareTo("==") == 0) {
                                try {
                                    dres = new BigDecimal(POP);
                                    str = String.valueOf(((BigDecimal) dres).compareTo(new BigDecimal(POP_2)) == 0);
                                } catch (Exception exception) {
                                    dres = POP;
                                    str = dres.toString().equals(POP_2) ? "true" : "false";
                                }
                            } else if (str.compareTo("!=") == 0 || str.compareTo("<>") == 0) {
                                try {
                                    dres = new BigDecimal(POP);
                                    str = String.valueOf(((BigDecimal) dres).compareTo(new BigDecimal(POP_2)) != 0);
                                } catch (Exception exception) {
                                    dres = POP;
                                    str = !dres.toString().equals(POP_2) ? "true" : "false";
                                }
                            } else if (str.compareToIgnoreCase("round") == 0 ) {
                                str = String.valueOf(Utilidades.redondear(new BigDecimal(POP).doubleValue(), new BigDecimal(POP_2).intValue()));
                            }

                            op.push(str);
                        } else if ("if".compareToIgnoreCase(str) == 0) {
                            if (Boolean.valueOf((String) op.pop()).booleanValue()) {
                                str = (String) op.pop();
                                op.pop();
                            } else {
                                op.pop();
                                str = (String) op.pop();
                            }
                            op.push(str);
                        } else {
                            op.push(str);
                        }
                    }
                    s.pop();
                    String pop3 = op.pop().toString();
                    s.push(pop3);
                } else {
                    s.push(str);
                }
            }
            if (s.size() + op.size() > 1) {
                throw new Exception("formula mal formada");
            }
        } catch (Exception e) {
            if (tipoRegistro == null && campo == null) {
                throw new IGFormatoException(e, "formula mal formada\n" + ecuacion, "Verifique la formula " + e.toString());
            } else {
                throw new IGFormatoException(e, "formula mal formada para el tipo de Regostro " + tipoRegistro + " en el campo " + campo + "\n" + ecuacion, "Verifique la formula " + e.toString());
            }
        }
        String returnn = replaceCaracteresEspeciale((String) s.pop());
//        System.out.println(returnn);
        return returnn;
    }

    private static String replaceCaracteresEspeciale(String str) {
        str = str.replaceAll("@ESPACIO", " ");
        str = str.replaceAll("@NADA", "");
        str = str.replaceAll("@", "");
        return str;
    }

    public static boolean validaExpresion(String ecuacion, String tipoRegistro, String campo) throws IGFormatoException {
        //ecuacion = ecuacion.replaceAll("\\(", " \\( ");
        //ecuacion = ecuacion.replaceAll("\\)", " \\) ");
        ecuacion = Matematica.organizeFormula(ecuacion);

        StringTokenizer stz = new StringTokenizer(ecuacion, " \t\n");
        String str = "";
        Stack s = new Stack();
        Stack op = new Stack();
        try {
            while (stz.hasMoreTokens()) {
                str = stz.nextToken();
                if (str.compareTo(")") == 0) {
                    while ("(".compareTo((String) s.peek()) != 0) {
                        str = (String) s.pop();
                        if ("*;/;+;-;*;>=;<=;>;<;=;<>;!=;round;ROUND;Round;".indexOf((new StringBuilder()).append(";").append(str).append(";").toString()) > 0) {
                            op.push((new StringBuilder()).append(op.pop()).append(str).append(op.pop()).toString());
                        } else if ("if".compareToIgnoreCase(str) == 0) {
                            str = (new StringBuilder()).append("if").append(op.pop()).append("then").append(op.pop()).append("else").append(op.pop()).toString();
                            op.push(str);
                        } else {
                            op.push(str);
                        }
                    }
                    s.pop();
                    s.push(op.pop());
                } else {
                    s.push(str);
                }
            }
        } catch (Exception e) {
            if (tipoRegistro == null && campo == null) {
                throw new IGFormatoException(e, "formula mal formada\n" + ecuacion, "Verifique la formula " + e.toString());
            } else {
                throw new IGFormatoException(e, "formula mal formada para el tipo de Regostro " + tipoRegistro + " en el campo " + campo + "\n" + ecuacion, "Verifique la formula " + e.toString());
            }

        }
        if (s.size() + op.size() > 1) {
            if (tipoRegistro == null && campo == null) {
                throw new IGFormatoException("formula mal formada\n" + ecuacion, "Verifique la formula");
            } else {
                throw new IGFormatoException("formula mal formada para el tipo de Regostro " + tipoRegistro + " en el campo " + campo + "\n" + ecuacion, "Verifique la formula");
            }
        } else {
            return true;
        }
    }

    public static void main(String args[]) throws IGFormatoException {
        
        String roun =""
                + "( IF ( = METVAL_41 9 ) 0  "
                + "( IF ( = METVAL_41 1 ) 0  "
                + "( IF ( = METVAL_41 2 ) 0  "
                + "( IF ( = TASAREF_35 CEC$ ) 0 "
                + "( IF ( = TASAREF_35 CRCDT ) 0 "
                + " ( IF ( = TASAREF_35 CECUVR ) 0 "
                + "     1 "
                + " ) "
                + ")"
                + ")"
                + ")"
                + ")"
                + ")";
                    
        //String roun="(round 8.36936 2.9)";
        System.out.println(validaExpresion(roun, roun, roun));
        System.out.println(evaluaExpresion(roun, roun, roun));
        /*         String expresion =
                "if (= 7 1 )\n" +
                "if (= 7 7 )\n" +
                "if (= 8 1 )\n";
        StringTokenizer st = new StringTokenizer(expresion, "\n");
        while (st.hasMoreElements()) {
            expresion = st.nextToken();
             expresion = organizeFormula(expresion, true);
            System.out.println(expresion);
            try {
                if (validaExpresion(expresion, "", "")) {
                    System.out.println(evaluaExpresion(expresion, "", ""));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }*/
    }
}
